#include "config.hxx"
#include "taskdefs.h"
#include "myfilelog.hxx"
#include "loghelper.hxx"
#include "wfaudiorecorder.hxx"
#include "udpsocketexception.hxx"
#include "udpsocket.hxx"
#include "secudpneter.hxx"
#include "priv/groupmgr.hxx"
#include "priv/tstatusmgr.hxx"
#include "priv/otconnmanager.hxx"
#include "priv/itconnmanager.hxx"
#include "priv/recordhandler.hxx"
#include "priv/mvhandler.hxx"
#include "priv/stconn.hxx"
#include "chatter.hxx"

Chatter::Chatter(tUpdateFunc update_func,tUInt32 myid,string myname,string centrals_host,tUInt32 centrals_cport,string log_file_path_and_name):
		_groupmgr(NULL),
		_tstatusmgr(NULL),
		_stconn(NULL),
		_update_func(update_func),
		_chatter_state(CHATTER_STATE_UNKNOWN),
		_myid(myid),
		_myname(myname),
		_centrals_host(centrals_host),
		_centrals_cport(centrals_cport),
		_log_file_path_and_name(log_file_path_and_name),
		_is_shutdown_requested(FALSE)
{
}

Chatter::~Chatter()
{
}

void Chatter::Shutdown(void)
{
	_is_shutdown_requested = TRUE;
}
string Chatter::GetMyName(void) const
{
	return _myname;
}
tUInt32 Chatter::GetMyId(void) const
{
	return _myid;
}
Chatter::tChatterState Chatter::ChatterState(void) const
{
	return _chatter_state;
}
tUInt32 Chatter::InvitePeer(tUInt32 userid)
{
	if (!_stconn)
		return 0;
	else
		return _stconn->InvitePeer(_myid,userid);
}
tUInt32 Chatter::Transfer(tUInt32 userid,string file_path_and_name)
{
	//return _otconnmanager->Transfer(userid,file_path_and_name);
	return 0;
}
tBool	Chatter::QueryTStatus(tUInt32 tid) const
{
	//return _otconnmanager->QueryStatus(tid);
	return FALSE;
}
tBool Chatter::CancelT( tUInt32 tid)
{
	return FALSE;
}
void Chatter::Update4StatusChanged(void)
{
	if (_update_func)
		_update_func();
}
void Chatter::Execute(Thread::Arg arg)
{
	/////////////////////////////////////Local variables////////////////////////////
	FileLog*		_filelog=NULL;
	UdpSocket*		udpsocket=NULL;
	SecUdpNeter*	secudpneter=NULL;
	OTConnManager*	otconnmanager=NULL;
	ITConnManager*	itconnmanager=NULL;
	RecordHandler*	recordhandler=NULL;
	WFAudioRecorder* audiorecorder=NULL;
	MVHandler* mvhandler=NULL;
	tUInt32 tid=0;

	TStatusMgr::tTaskType tasktype;
	TStatusMgr::tTState tstate = TStatusMgr::TASK_STATE_UNDEFINED;;
	float	progress=0;
	tBridgeMsg* reqestmsg = NULL;
	tBool exit_flag = FALSE;
	////////////////////////////////////////////////////////////////////////////////

	::DeleteFileA(_log_file_path_and_name.c_str());
	_filelog = new FileLog(_log_file_path_and_name);
	_filelog->SetMode(TRUE);
	_groupmgr = new GroupMgr(_filelog);
	_tstatusmgr = new TStatusMgr(_filelog);
	////////////////////////////////////////////////////////////////////////////////

	LOGINFO("Chatter starting up...");

	SetChatterState(CHATTER_STATE_STARTINGUP);

	/**
	 * At the very beginning, the axchatter has to connect to the Central Server
	 * for punching a hole for peer members to Tcp connect or send Udp voice data
	 */
	LOGINFO("Chatter logining...");

	try
	{
		udpsocket = new UdpSocket();
	}
	catch (UdpSocketException &e)
	{
		LOGERROR("RecordHandler::SendVoice:failed to instantiate a UdpSocket:"<<e.Description()<<",shutting down...");
		
		Shutdown();
	}

	_stconn = new STConn(_centrals_host,_centrals_cport,_groupmgr,_tstatusmgr,_filelog);

	_stconn->Start();

	tid = _stconn->Login(_myid,_myname);

	if (tid==0)
	{
		LOGERROR("Chatter Failed to login, aborting...");
		Shutdown();
	}
	else
	{
		while (!exit_flag)
		{
			if (!_tstatusmgr->QueryTStatus(CENTRALS_USER_ID,tid,tasktype,tstate,progress,&reqestmsg))
				LOGERROR("Chatter Failed to QueryTStatus for login.");

			switch(tstate)
			{
			case TStatusMgr::TASK_STATE_REQUEST_CONFIRMED:
			case TStatusMgr::TASK_STATE_FINISHED:
				LOGINFO("Chatter logined successfully.");
				exit_flag = TRUE;
				break;
			case TStatusMgr::TASK_STATE_REQUEST_CREATED:
			case TStatusMgr::TASK_STATE_REQUEST_SENT:
				break;
			case TStatusMgr::TASK_STATE_REQUEST_REJECTED:
			case TStatusMgr::TASK_STATE_REQUEST_TIMEOUTED:
			case TStatusMgr::TASK_STATE_REQUEST_UNAVAILABLE:
			case TStatusMgr::TASK_STATE_CANCELLED:
			case TStatusMgr::TASK_STATE_TERMINATED:
				LOGERROR("Chatter login failed,aborting...");
			default:
				LOGERROR("Chatter login got unknown state "<<tstate<<".");
				exit_flag = TRUE;
				Shutdown();
				break;
			}

			Thread::Yield();
		}
	}

	LOGINFO("Chatter register udp endpoints...");

	mvhandler = new MVHandler(_myid,_centrals_host,_centrals_cport,udpsocket,_groupmgr,_filelog);
	if (!mvhandler->RegisterUdpEndpoints())
	{
		LOGWARNING("Chatter failed to register udp endpoints,shutting down...");
		Shutdown();
	}
	else
	{
		LOGINFO("Chatter registering udp endpoints succeeded.");

		mvhandler->Start();

		audiorecorder = new WFAudioRecorder(BITS_PER_SAMPLE,SAMPLES_SEC,BLOCK_NB,BLOCK_SIZE,CHANNEL_NB,0,0/*_filelog*/);
		recordhandler = new RecordHandler(audiorecorder,udpsocket,_groupmgr,_filelog);
		recordhandler->Start();
		audiorecorder->SetCallBackThreadId(recordhandler->RealThreadId());
		audiorecorder->Start();

		LOGINFO("Chatter started.");
	}

	while (!_is_shutdown_requested)
	{
		SetChatterState(CHATTER_STATE_RUNNING);
		// Nothing to to, just looping ...
		Sleep(1);
	}

	// Here a shutdown singnal received.
	LOGDEBUG("Chatter::Execute:shutdown singnal received,shutting down...");

	_chatter_state = CHATTER_STATE_SHUTTINGDOWN;

	if (udpsocket)		udpsocket->Close();
	if (itconnmanager)	itconnmanager->Shutdown();
	if (mvhandler)		mvhandler->Shutdown();
	if (audiorecorder)	audiorecorder->Shutdown();
	if (recordhandler)	recordhandler->Shutdown();

	tUInt32 livecounter=4;
	tUInt32 counter = 0;
	while (counter != 0 && counter++ < 10)
	{
		if(mvhandler && Thread::FINISHED_STATE == mvhandler->State())
		{
			livecounter--;
			mvhandler->Join();
			delete mvhandler;
			mvhandler = NULL;
		}
		if(audiorecorder && Thread::FINISHED_STATE == audiorecorder->State()) 
		{
			livecounter--;
			audiorecorder->Join();
			audiorecorder->UnInit();
			delete audiorecorder;
			audiorecorder = NULL;
		}
		if(recordhandler && Thread::FINISHED_STATE == recordhandler->State())
		{
			livecounter--;
			recordhandler->Join();
			recordhandler->UnInit();
			delete recordhandler;
			recordhandler = NULL;
		}
		if(itconnmanager && Thread::FINISHED_STATE == itconnmanager->State())
		{
			livecounter--;
			itconnmanager->Join();
			delete itconnmanager;
			itconnmanager = NULL;
		}
	}

	if (livecounter)
		LOGWARNING("Chatter::Execute:Some thread(s) won't end,but sorry we will not join any longer...");

	LOGINFO("Chatter shutdowned.");

	if (udpsocket)		delete udpsocket;
	if (otconnmanager)	delete otconnmanager;
	if (itconnmanager)	delete itconnmanager;
	if (mvhandler)		delete mvhandler;
	if (recordhandler)	delete recordhandler;
	if (audiorecorder)	delete audiorecorder;
	if (_groupmgr)		delete _groupmgr;
	if (_filelog)		delete _filelog;

	SetChatterState(CHATTER_STATE_FINISHED);
}
void Chatter::SetChatterState(tChatterState chatterstate)
{
	if (_update_func&&chatterstate!=_chatter_state)
		_update_func();

	_chatter_state = chatterstate;
}